#include	"Engine.Compress.hpp"
#include	"MiniZ/miniz.h"

#include	<cstring>

namespace Engine {

	size_t Zip::CalcCompressSize(size_t uSizeSrc) {
		return (size_t)mz_compressBound(uSizeSrc);
	}

	Zip::EState Zip::Compress(char * pDst, size_t & uSizeDst, const char * pSrc, size_t uSizeSrc) {
		mz_ulong uDst = (mz_ulong)uSizeDst;
		int nRet = mz_compress((unsigned char *)pDst, &uDst, (const unsigned char *)pSrc, (mz_ulong)uSizeSrc);
		uSizeDst = (size_t)uDst;
		return (Zip::EState)nRet;
	}

	Zip::EState Zip::Uncompress(char * pDst, size_t & uSizeDst, const char * pSrc, size_t uSizeSrc) {
		mz_ulong uDst = (mz_ulong)uSizeDst;
		int nRet = mz_uncompress((unsigned char *)pDst, &uDst, (const unsigned char *)pSrc, (mz_ulong)uSizeSrc);
		uSizeDst = (size_t)uDst;
		return (Zip::EState)nRet;
	}

	Zip::Zip() : _pZip(new mz_zip_archive), _bValid(false), _vInfos() {
		::memset(_pZip, 0, sizeof(mz_zip_archive));
	}

	Zip::~Zip() {
		Close();
	}

	bool Zip::FromFile(const char * szPath) {
		Close();

		if (!mz_zip_reader_init_file(_pZip, szPath, 0))
			return false;

		size_t nCount = mz_zip_reader_get_num_files(_pZip);
		for (size_t nIdx = 0; nIdx < nCount; ++nIdx) {
			mz_zip_archive_file_stat iStat;
			if (!mz_zip_reader_file_stat(_pZip, nIdx, &iStat)) continue;
			ZipItem iInfo;
			::memcpy(iInfo.szFile, iStat.m_filename, 256);
			iInfo.bDir = mz_zip_reader_is_file_a_directory(_pZip, nIdx) == 1;
			iInfo.uSize = (size_t)iStat.m_uncomp_size;
			_vInfos.push_back(iInfo);
		}

		_bValid = true;
		return true;
	}

	bool Zip::FromMem(const char * pData, size_t uSize) {
		Close();

		if (!mz_zip_reader_init_mem(_pZip, pData, uSize, 0))
			return false;

		size_t nCount = mz_zip_reader_get_num_files(_pZip);
		for (size_t nIdx = 0; nIdx < nCount; ++nIdx) {
			mz_zip_archive_file_stat iStat;
			if (!mz_zip_reader_file_stat(_pZip, nIdx, &iStat)) continue;
			ZipItem iInfo;
			::memcpy(iInfo.szFile, iStat.m_filename, 256);
			iInfo.bDir = mz_zip_reader_is_file_a_directory(_pZip, nIdx) == 1;
			iInfo.uSize = (size_t)iStat.m_uncomp_size;
			_vInfos.push_back(iInfo);
		}

		_bValid = true;
		return true;
	}
	
	ZipItem * Zip::GetItemInfo(const char * szItem) {
		for (auto it = _vInfos.begin(); it != _vInfos.end(); ++it) {
			if (::strncmp(szItem, it->szFile, 256) == 0) {
				return &(*it);
			}
		}
		return nullptr;
	}

	bool Zip::Extra(const char * szItem, char * pMem, size_t uSize) {
		if (!_bValid) return false;
		return mz_zip_reader_extract_file_to_mem(_pZip, szItem, pMem, uSize, 0) == 1;
	}
		
	void Zip::Close() {
		if (_bValid) {
			mz_zip_reader_end(_pZip);
			::memset(_pZip, 0, sizeof(mz_zip_archive));
			_bValid = false;
		}
		_vInfos.clear();
	}
}